package pool

import (
	"errors"
	"sync"
	"sync/atomic"
	"worm/base"
	"worm/pool"
	toolBuffer "worm/tool/buffer"
)

type myPool struct {
	//缓冲器的统一容量
	bufferCap uint32
	//缓冲器的最大数量
	maxBufferNumber uint32
	//缓冲器的实际数量
	bufferNumber uint32
	//池中数据的总数
	total uint64
	//存放缓冲器的通道
	bufCh chan pool.Buffer
	//缓冲池的关闭状态 0，未关闭，1已关闭
	closed uint32
	//读写锁
	rwlock sync.RWMutex
}

func (pool *myPool) BufferCap(num uint32) {
	pool.bufferCap = num
}

func (pool *myPool) MaxBufferNumber(num uint32) {
	pool.maxBufferNumber = num
}

func (pool *myPool) BufferNum(num uint32) {
	pool.bufferNumber = num
}

func (pool *myPool) Total(num uint64) {
	pool.total = num
}

func (pool *myPool) Close() bool {
	if atomic.CompareAndSwapUint32(&pool.closed, 0, 1) {
		pool.rwlock.Lock()
		defer pool.rwlock.Unlock()
		close(pool.bufCh)
		for buf := range pool.bufCh {
			buf.Close()
		}
		return true
	}
	return false
}

func (pool *myPool) Closed() bool {
	if atomic.LoadUint32(&pool.closed) == 0 {
		return true
	}
	return false
}

func (pool *myPool) Put(datum interface{}) (err error) {
	if pool.Closed() {
		return errors.New(string(base.POOL_CLOSED))
	}
	var count uint32
	maxCount := pool.bufferNumber * 5
	var ok bool

	//出管道
	for buf := range pool.bufCh {
		ok, err = pool.PutData(buf, datum, &count, maxCount)
		if ok || err != nil {
			break
		}

	}
	return
}

func (pool *myPool) PutData(buffer pool.Buffer, datum interface{}, count *uint32, maxCount uint32) (ok bool, err error) {
	if pool.Closed() {
		return false, errors.New(string(base.POOL_CLOSED))
	}
	defer func() {
		pool.rwlock.RLock()
		if pool.Closed() {
			atomic.AddUint32(&pool.bufferNumber, ^uint32(0))
			err = errors.New(string(base.POOL_CLOSED))
		} else {
			//取出的缓冲器放入池子中
			pool.bufCh <- buffer
		}
		pool.rwlock.Unlock()
	}()

	ok, err = buffer.Put(datum)
	if ok {
		//数据量加一
		atomic.AddUint64(&pool.total, 1)
		return
	}
	if err != nil {
		return
	}

	(*count)++

	if *count >= maxCount && pool.bufferNumber < pool.maxBufferNumber {
		pool.rwlock.Lock()
		//缓冲器的数量小于最大缓冲池数
		if pool.bufferNumber < pool.maxBufferNumber {
			if pool.Closed() {
				pool.rwlock.Unlock()
				return
			}
			//创建缓冲器
			newbuf, _ := toolBuffer.NewBuffer(pool.bufferCap)
			//放入数据
			newbuf.Put(datum)
			//缓冲器放入池中
			pool.bufCh <- newbuf
			//缓冲器加1
			atomic.AddUint32(&pool.bufferNumber, 1)
			//数据量加1
			atomic.AddUint64(&pool.total, 1)
			ok = true
		}
		pool.rwlock.Unlock()
		*count = 0
	}

	return
}

func (pool *myPool) Get() (datum interface{}, err error) {
	if pool.Closed() {
		return false, errors.New(string(base.POOL_CLOSED))
	}

	var count uint32
	maxCount := pool.bufferNumber * 10

	for buf := range pool.bufCh {
		datum, err = pool.getData(buf, &count, maxCount)
		if datum != nil || err != nil {
			break
		}
	}

	return
}

func (pool *myPool) getData(buffer pool.Buffer, count *uint32, maxCount uint32) (datum interface{}, err error) {
	if pool.Closed() {
		return nil, errors.New(string(base.POOL_CLOSED))
	}

	defer func() {
		//获取数据的次数大于maxCount，缓冲器中数据为0，缓冲池中的缓冲器数量大于1
		//关掉当前缓冲器，并不归还缓冲池
		if *count >= maxCount && buffer.Len() <= 0 && pool.bufferNumber > 1 {
			buffer.Close()
			atomic.AddUint32(&pool.bufferNumber, ^uint32(0))
			*count = 0
			return
		}

		pool.rwlock.Unlock()
		if pool.Closed() {
			atomic.AddUint32(&pool.bufferNumber, ^uint32(0))
			err = errors.New(string(base.POOL_CLOSED))
		} else {
			pool.bufCh <- buffer
		}
		pool.rwlock.Unlock()
	}()

	//获取数据
	datum, err = buffer.Get()
	if datum != nil {
		atomic.AddUint64(&pool.total, ^uint64(0))
		return
	}

	if err != nil {
		return
	}

	(*count)++
	return
}
